package cn.sytton.taffecloud.serivce.auth.security.sms;

import cn.sytton.taffecloud.serivce.auth.security.sms.code.SmsCodeFactory;
import cn.sytton.taffecloud.common.base.security.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;

/**
 * 短信验证码AuthenticationProvider
 *
 * @author skyrock
 */
@Slf4j
@Component
public class SmsCodeAuthenticationProvider implements AuthenticationProvider, InitializingBean {

    @Resource
    private ISmsCodeDetailsService smsCodeDetailsService;

    @Resource
    private SmsCodeFactory smsCodeFactory;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        UserDetails user = smsCodeDetailsService.loadUserByCellphone((String) authentication.getPrincipal());

        //验证
        additionalAuthenticationChecks((LoginUser)user, (SmsCodeAuthenticationToken)authentication);

        SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(user, authentication.getCredentials(), user.getAuthorities());

        authenticationResult.setDetails(authenticationResult.getDetails());

        return authenticationResult;
    }

    protected void additionalAuthenticationChecks(LoginUser loginUser, SmsCodeAuthenticationToken authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            throw new BadCredentialsException("验证码不能为空");
        } else {
            String presentedCode = authentication.getCredentials().toString();
            if (smsCodeFactory.verify(loginUser.getCellphone(), presentedCode)) {
                //验证成功后删除该验证码
                smsCodeFactory.delSms(loginUser.getCellphone());
            } else {
                throw new BadCredentialsException("验证码错误或已过期");
            }
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }

    @Override
    public void afterPropertiesSet() {
        Assert.notNull(this.smsCodeDetailsService, "A SmsCodeDetailsService must be set");
    }
}
